﻿// -----------------------------------------------------------------------
// <copyright file="MonthlyCalendar.cs" company="The Usual Dosage">
// © 2013 by Matthew M. Martin
// </copyright>
// -----------------------------------------------------------------------

namespace Cadence.NET.Calendars
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Cadence.NET.BaseClasses;

    /// <summary>
    /// Describes the methods and properties of a month-based calendar.
    /// </summary>
    public class MonthlyCalendar : ICalendar
    {
        #region Properties

        private List<int> runMonths;
        /// <summary>
        /// Gets or sets the run months.
        /// </summary>
        /// <value>
        /// The run months.
        /// </value>
        public List<int> RunMonths
        {
            get
            {
                return runMonths;
            }
            set
            {
                var invalidMonths = value.Where(m => m <= 0 || m > 12);
                if (invalidMonths != null && invalidMonths.Count() > 0)
                {
                    throw new InvalidOperationException("Month must be a value between 1 and 12.");
                }
                else
                {
                    runMonths = value;
                }
            }
        }

        /// <summary>
        /// Gets or sets the Months that the task will absolutely not be run.
        /// </summary>
        /// <value>
        /// The exclude Months.
        /// </value>
        private List<int> excludeMonths;
        public List<int> ExcludeMonths
        {
            get
            {
                return excludeMonths;
            }
            set
            {
                var invalidMonths = value.Where(m => m <= 0 || m > 12);
                if (invalidMonths != null && invalidMonths.Count() > 0)
                {
                    throw new InvalidOperationException("Month must be a value between 1 and 12.");
                }
                else
                {
                    excludeMonths = value;
                }
            }
        }

        /// <summary>
        /// Gets or sets the Months that the task will be run, regardless.
        /// </summary>
        /// <value>
        /// The include Months.
        /// </value>
        private List<int> overrideMonths;
        public List<int> OverrideMonths
        {
            get
            {
                return overrideMonths;
            }
            set
            {
                var invalidMonths = value.Where(m => m <= 0 || m > 12);
                if (invalidMonths != null && invalidMonths.Count() > 0)
                {
                    throw new InvalidOperationException("Month must be a value between 1 and 12.");
                }
                else
                {
                    overrideMonths = value;
                }
            }
        }

        /// <summary>
        /// Gets or sets the timezone offset from UTC.
        /// </summary>
        /// <value>
        /// The timezone offset.
        /// </value>
        public int? TimezoneUTCOffset
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the current date time.
        /// </summary>
        public DateTime CurrentDateTime
        {
            get
            {
                if (TimezoneUTCOffset.HasValue)
                    return DateTime.UtcNow.AddHours(TimezoneUTCOffset.Value);
                else
                    return DateTime.UtcNow;
            }
        }

        #endregion Properties

        #region Interface Implementation

        /// <summary>
        /// When implemented in a derived class, checks the time configured, and indicates whether this instance can run.
        /// </summary>
        /// <returns>
        ///   <c>true</c> if this instance can run; otherwise, <c>false</c>.
        /// </returns>
        public bool CanRun()
        {
            int currentMonth = CurrentDateTime.Month;

            if (OverrideMonths != null && OverrideMonths.Contains(currentMonth))
                return true;
            else if (ExcludeMonths != null && ExcludeMonths.Contains(currentMonth))
                return false;
            else if (RunMonths.Contains(currentMonth))
                return true;
            else
                return false;
        }

        #endregion Interface Implementation
    }
}
